﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AlgoritmTeorija
{
    public partial class HeapSort : Form
    {

        protected string FileName = "Data.txt";
        private BackgroundWorker _bw = new BackgroundWorker();

        public HeapSort()
        {
            InitializeComponent();
            _bw.DoWork += bw_DoWork;
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            if(rdFile.Checked)
                doHeapSort();
            else
            {
                doHeapSortRAM();
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            DisplayData(FileName);
            _bw.RunWorkerAsync();
        }

        private void btnDisplayData_Click(object sender, EventArgs e)
        {
            DisplayData(FileName);
        }

        private void btnRandom_Click(object sender, EventArgs e)
        {
            RandomDataHelper rd = new RandomDataHelper(FileName);
            rd.GenerateRandomNumbers(Convert.ToInt32(txtQuantity.Text));
            DisplayData(FileName);

        }

        private void DisplayData(string fileName)
        {
            FileHelper fh = new FileHelper(fileName, FileMode.Open);
            txtData.Text = fh.GetAllFile();
        }

        private void txtQuantity_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
        }


        #region HEAP SORT
        private void doHeapSort ()
        {
            FileHelper fh = new FileHelper(FileName, FileMode.Open);
            fh.CopyFile(FileName);
            progressBar.Invoke((MethodInvoker) delegate{progressBar.Maximum = fh.Length;});
            TimeHelper th = new TimeHelper();
            th.StartTimer();

            progressBarTotal.Invoke((MethodInvoker)delegate{progressBarTotal.Maximum = (fh.Length - 1)/2;});
            //build the initial heap
            for (int i = (fh.Length - 1) / 2; i >= 0; i--)
            {
                Adjust(fh, i, fh.Length - 1);
                progressBarTotal.Invoke((MethodInvoker)delegate{progressBarTotal.Value = progressBarTotal.Maximum - i;});
            }

            //swap root node and the last heap node
            for (int i = fh.Length - 1; i >= 1; i--)
            {
                int Temp = fh.ReadBinary(0);
                fh.WriteBinary(0, fh.ReadBinary(i));
                fh.WriteBinary(i, Temp);
                Adjust(fh, 0, i - 1);
                progressBar.Invoke((MethodInvoker)delegate{progressBar.Value = progressBar.Maximum - i + 1;});
            }

            th.StopTimer();
            txtResult.Invoke((MethodInvoker) delegate{txtResult.Text = fh.GetAllFile();});
            MessageBox.Show("Veikimo laikas: " + th.GetDuration().ToString() + "\r\nOperacijų skaičius: " + fh.opCount,
                            "Informacija", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void Adjust(FileHelper list, int i, int m)
        {
            int Temp = list.ReadBinary(i);
            int j = i * 2 + 1;
            while (j <= m)
            {
                //more children
                if (j < m)
                    if (list.ReadBinary(j) < list.ReadBinary(j + 1))
                        j = j + 1;

                //compare roots and the older children
                if (Temp < list.ReadBinary(j))
                {
                   list.WriteBinary(i, list.ReadBinary(j));
                    i = j;
                    j = 2 * i + 1;
                }
                else
                    j = m + 1;
            }
            list.WriteBinary(i, Temp);
        }

        private void doHeapSortRAM()
        {
            int[] list = null;
            string[] tempList = null;

            FileHelper fh = new FileHelper(FileName, FileMode.Open);
            fh.CopyFile(FileName);
            progressBar.Invoke((MethodInvoker)delegate { progressBar.Maximum = fh.Length; });

            tempList = fh.GetAllFile().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            list = new int[tempList.Length];
            int currIndex = 0;
            foreach (string str in tempList)
            {
                list[currIndex] = Convert.ToInt32(str);
                currIndex++;
            }
            TimeHelper th = new TimeHelper();
            th.StartTimer();

            progressBarTotal.Invoke((MethodInvoker)delegate { progressBarTotal.Maximum = (list.Length - 1) / 2; });
            //build the initial heap
            for (int i = (list.Length - 1) / 2; i >= 0; i--)
            {
                AdjustRAM(list, i, list.Length - 1);
                progressBarTotal.Invoke((MethodInvoker)delegate { progressBarTotal.Value = progressBarTotal.Maximum - i; });
            }

            //swap root node and the last heap node
            for (int i = list.Length - 1; i >= 1; i--)
            {
                int Temp = list[0];
                list[0] =  list[i];
                list[i] = Temp;
                AdjustRAM(list, 0, i - 1);
                progressBar.Invoke((MethodInvoker)delegate { progressBar.Value = progressBar.Maximum - i + 1; });
            }

            th.StopTimer();
                        StringBuilder builder = new StringBuilder();
            Array.ForEach(list, x => builder.Append(x + "\r\n"));
            txtResult.Text = builder.ToString();
            MessageBox.Show("Veikimo laikas: " + th.GetDuration().ToString(),
                            "Informacija", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void AdjustRAM(int[] list, int i, int m)
        {
            int Temp = list[i];
            int j = i * 2 + 1;
            while (j <= m)
            {
                //more children
                if (j < m)
                    if (list[j] < list[j + 1])
                        j = j + 1;

                //compare roots and the older children
                if (Temp < list[j])
                {
                    list[i] = list[j];
                    i = j;
                    j = 2 * i + 1;
                }
                else
                    j = m + 1;
            }
            list[i] = Temp;
        }
        #endregion


    }
}
